<template>
  <view class="mask flex-center">
    <view class="content botton-radius">
      <view class="content-top">
        <text class="content-top-text">{{ title }}</text>
        <image
          class="content-top"
          style="top: 0"
          width="100%"
          height="100%"
          src="../static/bg_top.png"
        >
        </image>
      </view>
      <view class="content-header"></view>
      <view class="content-body">
        <view class="title">
          <text>{{ subTitle }}</text>
          <text style="padding-left: 20rpx; font-size: 28rpx; color: #666"
            >v.{{ version }}</text
          >
        </view>
        <view class="body">
          <scroll-view class="box-des-scroll" scroll-y="true">
            <text class="box-des">
              {{ contents }}
            </text>
          </scroll-view>
        </view>
        <view class="footer flex-center">
          <template v-if="isiOS">
            <button
              class="content-button"
              style="border: none; color: #fff"
              plain
              @click="jumpToAppStore"
            >
              {{ downLoadBtnTextiOS }}
            </button>
          </template>
          <template v-else>
            <template v-if="!downloadSuccess">
              <view class="progress-box flex-column" v-if="downloading">
                <progress
                  class="progress"
                  border-radius="35"
                  :percent="downLoadPercent"
                  activeColor="#EA5646"
                  show-info
                  stroke-width="10"
                />
                <view
                  style="
                    width: 100%;
                    font-size: 28rpx;
                    display: flex;
                    justify-content: space-around;
                  "
                >
                  <text>{{ downLoadingText }}</text>
                  <text>({{ downloadedSize }}/{{ packageFileSize }}M)</text>
                </view>
              </view>

              <button
                v-else
                class="content-button"
                style="border: none; color: #fff"
                plain
                @click="downloadPackage"
              >
                {{ downLoadBtnText }}
              </button>
            </template>
            <button
              v-else-if="downloadSuccess && !installed"
              class="content-button"
              style="border: none; color: #fff"
              plain
              :loading="installing"
              :disabled="installing"
              @click="installPackage"
            >
              {{ installing ? "正在安装……" : "下载完成，立即安装" }}
            </button>

            <button
              v-if="installed && isWGT"
              class="content-button"
              style="border: none; color: #fff"
              plain
              @click="restart"
            >
              安装完毕，点击重启
            </button>
          </template>
        </view>
      </view>

      <image
        v-if="!is_mandatory"
        class="close-img"
        src="../static/app_update_close.png"
        @click.stop="closeUpdate"
      ></image>
    </view>
  </view>
</template>

<script>
const localFilePathKey = "__localFilePath__";
const platform_iOS = "iOS";
let downloadTask = null;

/**
 * 对比版本号，如需要，请自行修改判断规则
 * 支持比对	("3.0.0.0.0.1.0.1", "3.0.0.0.0.1")	("3.0.0.1", "3.0")	("3.1.1", "3.1.1.1") 之类的
 * @param {Object} v1
 * @param {Object} v2
 * v1 > v2 return 1
 * v1 < v2 return -1
 * v1 == v2 return 0
 */
function compare(v1 = "0", v2 = "0") {
  v1 = String(v1).split(".");
  v2 = String(v2).split(".");
  const minVersionLens = Math.min(v1.length, v2.length);
  let result = 0;
  for (let i = 0; i < minVersionLens; i++) {
    const curV1 = Number(v1[i]);
    const curV2 = Number(v2[i]);

    if (curV1 > curV2) {
      result = 1;
      break;
    } else if (curV1 < curV2) {
      result = -1;
      break;
    }
  }
  if (result === 0 && v1.length !== v2.length) {
    const v1BiggerThenv2 = v1.length > v2.length;
    const maxLensVersion = v1BiggerThenv2 ? v1 : v2;
    for (let i = minVersionLens; i < maxLensVersion.length; i++) {
      const curVersion = Number(maxLensVersion[i]);
      if (curVersion > 0) {
        v1BiggerThenv2 ? (result = 1) : (result = -1);
        break;
      }
    }
  }
  return result;
}

export default {
  data() {
    return {
      // 从之前下载安装
      installForBeforeFilePath: "",

      // 安装
      installed: false,
      installing: false,

      // 下载
      downloadSuccess: false,
      downloading: false,

      downLoadPercent: 0,
      downloadedSize: 0,
      packageFileSize: 0,

      tempFilePath: "", // 要安装的本地包地址

      // 默认安装包信息
      title: "更新日志",
      contents: "",
      is_mandatory: false,

      // 可自定义属性
      subTitle: "发现新版本",
      downLoadBtnTextiOS: "立即跳转更新",
      downLoadBtnText: "立即下载更新",
      downLoadingText: "安装包下载中，请稍后…",
    };
  },
  onLoad({ local_storage_key }) {
    if (!local_storage_key) {
      console.error("local_storage_key为空，请检查后重试");
      uni.navigateBack();
      return;
    }

    const localPackageInfo = uni.getStorageSync(local_storage_key);
    if (!localPackageInfo) {
      console.error("安装包信息为空，请检查后重试");
      uni.navigateBack();
      return;
    }

    const requiredKey = ["version", "url", "type"];
    for (let key in localPackageInfo) {
      if (requiredKey.indexOf(key) !== -1 && !localPackageInfo[key]) {
        console.error(`参数 ${key} 必填，请检查后重试`);
        uni.navigateBack();
        return;
      }
    }

    Object.assign(this, localPackageInfo);
    this.checkLocalStoragePackage();
  },
  onBackPress() {
    // 强制更新不允许返回
    if (this.is_mandatory) {
      return true;
    }

    downloadTask && downloadTask.abort();
  },
  computed: {
    isWGT() {
      return this.type === "wgt";
    },
    isiOS() {
      return !this.isWGT ? this.platform.includes(platform_iOS) : false;
    },
  },
  methods: {
    checkLocalStoragePackage() {
      // 如果已经有下载好的包，则直接提示安装
      const localFilePathRecord = uni.getStorageSync(localFilePathKey);
      if (localFilePathRecord) {
        const { version, savedFilePath } = localFilePathRecord;
        // 比对版本
        if (compare(version, this.version) === 0) {
          this.downloadSuccess = true;
          this.installForBeforeFilePath = savedFilePath;
          this.tempFilePath = savedFilePath;
        } else {
          // 如果保存的包版本小，则直接删除
          this.deleteSavedFile(savedFilePath);
        }
      }
    },
    async closeUpdate() {
      if (this.downloading) {
        if (this.is_mandatory) {
          return uni.showToast({
            title: "下载中，请稍后……",
            icon: "none",
            duration: 500,
          });
        }
        uni.showModal({
          title: "是否取消下载？",
          cancelText: "否",
          confirmText: "是",
          success: (res) => {
            if (res.confirm) {
              downloadTask && downloadTask.abort();
              uni.navigateBack();
            }
          },
        });
        return;
      }

      if (this.downloadSuccess && this.tempFilePath) {
        // 包已经下载完毕，稍后安装，将包保存在本地
        await this.saveFile(this.tempFilePath, this.version);
        uni.navigateBack();
        return;
      }

      uni.navigateBack();
    },
    downloadPackage() {
      this.downloading = true;

      //下载包
      downloadTask = uni.downloadFile({
        url: this.url,
        success: (res) => {
          if (res.statusCode == 200) {
            this.downloadSuccess = true;
            this.tempFilePath = res.tempFilePath;

            // 强制更新，直接安装
            if (this.is_mandatory) {
              this.installPackage();
            }
          }
        },
        complete: () => {
          this.downloading = false;

          this.downLoadPercent = 0;
          this.downloadedSize = 0;
          this.packageFileSize = 0;

          downloadTask = null;
        },
      });

      downloadTask.onProgressUpdate((res) => {
        this.downLoadPercent = res.progress;
        this.downloadedSize = (
          res.totalBytesWritten / Math.pow(1024, 2)
        ).toFixed(2);
        this.packageFileSize = (
          res.totalBytesExpectedToWrite / Math.pow(1024, 2)
        ).toFixed(2);
      });
    },
    installPackage() {
      // #ifdef APP-PLUS
      // wgt资源包安装
      if (this.isWGT) {
        this.installing = true;
      }

      plus.runtime.install(
        this.tempFilePath,
        {
          force: false,
        },
        async (res) => {
          this.installing = false;
          this.installed = true;

          // 如果是安装之前的包，安装成功后删除之前的包
          if (this.installForBeforeFilePath) {
            await this.deleteSavedFile(this.installForBeforeFilePath);
            this.installForBeforeFilePath = "";
          }

          // wgt包，安装后会提示 安装成功，是否重启
          if (this.isWGT) {
            // 强制更新安装完成重启
            if (this.is_mandatory) {
              uni.showLoading({
                icon: "none",
                title: "安装成功，正在重启……",
              });

              setTimeout(() => {
                uni.hideLoading();
                this.restart();
              }, 1000);
            } else {
              uni.showLoading({
                icon: "none",
                title: "安装成功，重启应用体验新版",
                duration: 1000,
              });
            }
          }
        },
        async (err) => {
          // 如果是安装之前的包，安装失败后删除之前的包
          if (this.installForBeforeFilePath) {
            await this.deleteSavedFile(this.installForBeforeFilePath);
            this.installForBeforeFilePath = "";
          }

          // 安装失败需要重新下载安装包
          this.installed = false;

          uni.showModal({
            title: "更新失败",
            content: err.message,
            showCancel: false,
          });
        }
      );

      // 非wgt包，安装跳出覆盖安装，此处直接返回上一页
      if (!this.isWGT) {
        uni.navigateBack();
      }
      // #endif
    },
    restart() {
      this.installed = false;
      // #ifdef APP-PLUS
      //更新完重启app
      plus.runtime.restart();
      // #endif
    },
    async saveFile(tempFilePath, version) {
      const [err, res] = await uni.saveFile({
        tempFilePath,
      });
      if (err) {
        return;
      }
      uni.setStorageSync(localFilePathKey, {
        version,
        savedFilePath: res.savedFilePath,
      });
    },
    deleteSavedFile(filePath) {
      uni.removeStorageSync(localFilePathKey);
      return uni.removeSavedFile({
        filePath,
      });
    },
    jumpToAppStore() {
      plus.runtime.openURL(this.url);
    },
  },
};
</script>

<style>
page {
  background: transparent;
}

.flex-center {
  /* #ifndef APP-NVUE */
  display: flex;
  /* #endif */
  justify-content: center;
  align-items: center;
}

.mask {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.65);
}

.botton-radius {
  border-bottom-left-radius: 30rpx;
  border-bottom-right-radius: 30rpx;
}

.content {
  position: relative;
  top: 0;
  width: 600rpx;
  background-color: #fff;
  box-sizing: border-box;
  padding: 0 50rpx;
  font-family: Source Han Sans CN;
}

.text {
  /* #ifndef APP-NVUE */
  display: block;
  /* #endif */
  line-height: 200px;
  text-align: center;
  color: #ffffff;
}

.content-top {
  position: absolute;
  top: -195rpx;
  left: 0;
  width: 600rpx;
  height: 270rpx;
}

.content-top-text {
  font-size: 45rpx;
  font-weight: bold;
  color: #f8f8fa;
  position: absolute;
  top: 120rpx;
  left: 50rpx;
  z-index: 1;
}

.content-header {
  height: 70rpx;
}

.title {
  font-size: 33rpx;
  font-weight: bold;
  color: #ea5646;
  line-height: 38px;
}

.footer {
  height: 150rpx;
  display: flex;
  align-items: center;
  justify-content: space-around;
}

.box-des-scroll {
  box-sizing: border-box;
  padding: 0 40rpx;
  height: 200rpx;
  text-align: left;
}

.box-des {
  font-size: 26rpx;
  color: #000000;
  line-height: 50rpx;
}

.progress-box {
  width: 100%;
}

.progress {
  width: 90%;
  height: 40rpx;
  border-radius: 35px;
}

.close-img {
  width: 70rpx;
  height: 70rpx;
  z-index: 1000;
  position: absolute;
  bottom: -120rpx;
  left: calc(50% - 70rpx / 2);
}

.content-button {
  text-align: center;
  flex: 1;
  font-size: 30rpx;
  font-weight: 400;
  color: #ffffff;
  width: 480rpx;
  height: 80rpx;
  line-height: 80rpx;
  background-image: linear-gradient(90deg, #ea5646, #f36354) !important;
}

.flex-column {
  display: flex;
  flex-direction: column;
  align-items: center;
}
</style>
